package com.ruicar.afs.cloud.afscase.dispatch.component;

import com.ruicar.afs.cloud.afscase.dispatch.DispatchContext;
import com.ruicar.afs.cloud.afscase.dispatch.annotation.Dispatch;
import com.ruicar.afs.cloud.afscase.dispatch.enums.DispatchTypeEnum;
import com.ruicar.afs.cloud.afscase.dispatch.service.DispatchBaseServcie;
import com.ruicar.afs.cloud.afscase.dispatch.service.IDispatchBeforService;
import com.ruicar.afs.cloud.afscase.dispatch.service.IDispatchServcie;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author cheng.bi 分单任务组件
 */
@Component
@Slf4j
public class DispatchComponent extends BaseComponent implements ApplicationListener<ApplicationReadyEvent> {

    private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
    private static List<DispatchBaseServcie> servicesList = new ArrayList<DispatchBaseServcie>();

    private static MultiValueMap<DispatchTypeEnum, DispatchBaseServcie> servicesMap = new LinkedMultiValueMap<DispatchTypeEnum, DispatchBaseServcie>();

    @PostConstruct
    private void init() {
        Map<String, IDispatchBeforService> serMap = getBeanMapWithAnnotation(IDispatchBeforService.class,
                Dispatch.class);
        Stack<IDispatchBeforService> stack = new Stack<IDispatchBeforService>(); // 利用栈的特性做任务依赖执行排序
        stack.addAll(serMap.values());
        while (!stack.isEmpty()) {
            DispatchBaseServcie service = (DispatchBaseServcie) stack.pop();
            Dispatch dispatch = service.getClass().getAnnotation(Dispatch.class);
            service.setAsyn(dispatch.asyn());
            service.setSkip(dispatch.errSkip());
            service.setName(dispatch.name());
            DispatchTypeEnum[] types = dispatch.group(); //获取分组
            DispatchTypeEnum type = null;
            if (types != null && types.length > 0) {
                type = types[0];
            } else {
                type = DispatchTypeEnum.OTHER;
            }
            List<DispatchBaseServcie> serviceList = servicesMap.get(type);

            if (serviceList == null) {
                serviceList = new ArrayList<DispatchBaseServcie>();
            }
            if (serviceList.contains(service)) {

            } else if (StringUtils.isEmpty(dispatch.dependsOn())
                    || serviceList.contains(serMap.get(dispatch.dependsOn()))) {
                log.info("初始化分单前置任务{}任务，任务组{}", dispatch.name(), type.getName());
                servicesMap.add(type, service);
            } else {
                Assert.isTrue(serMap.get(dispatch.dependsOn()) != null,
                        MessageFormat.format("Error relevance bean with name {0}", dispatch.dependsOn()));
                stack.push(service);
                stack.push(serMap.get(dispatch.dependsOn()));
            }
        }

    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        EXECUTOR_SERVICE.scheduleWithFixedDelay(() -> {
            SpringContextHolder.getBean(IDispatchServcie.class).excutorProcess(new DispatchContext<>());
        }, 2, 60, TimeUnit.SECONDS);
    }

    public static List<DispatchBaseServcie> getServicesList() {
        return servicesList;
    }

    public static MultiValueMap<DispatchTypeEnum, DispatchBaseServcie> getServicesMap() {
        return servicesMap;
    }
}
